home *** CD-ROM | disk | FTP | other *** search
- /* $Id: ps.c,v 1.33 1995/03/11 20:27:13 mjl Exp $
- * $Log: ps.c,v $
- * Revision 1.33 1995/03/11 20:27:13 mjl
- * All drivers: eliminated unnecessary variable initializations, other cleaning
- * up.
- *
- * Revision 1.32 1995/01/10 09:37:00 mjl
- * Fixed braindamage incurred last update. Now switches to transparent
- * background mode (no page fill) automatically if background color is white.
- * Useful for including color EPSF files into TeX or whatever.
- *
- * Revision 1.31 1995/01/09 21:48:34 mjl
- * Fixed background color fill to cover the entire page, including margin
- * area.
- *
- * Revision 1.30 1994/09/23 07:36:27 mjl
- * Now generates ps files with the correct PLplot version number written.
- *
- * Revision 1.29 1994/09/01 22:28:09 mjl
- * Fixed bug in current point update after state change.
- *
- * Revision 1.28 1994/08/27 03:40:32 mjl
- * Fix to allow cmap1 color selections to appear in grayscale. Contributed
- * by Radey Shouman.
- */
-
- /* ps.c
-
- PLplot PostScript device driver.
- */
- #include "plDevs.h"
-
- #ifdef PLD_ps
-
- #include "plplotP.h"
- #include "drivers.h"
-
- #include <string.h>
- #include <time.h>
-
- /* Prototypes for functions in this file. */
-
- static char *ps_getdate (void);
- static void ps_init (PLStream *);
- static void fill_polygon (PLStream *pls);
-
- /* top level declarations */
-
- #define LINELENGTH 78
- #define COPIES 1
- #define XSIZE 540 /* 7.5 x 10 [inches] */
- #define YSIZE 720 /* (72 points = 1 inch) */
- #define ENLARGE 5
- #define XPSSIZE ENLARGE*XSIZE
- #define YPSSIZE ENLARGE*YSIZE
- #define XOFFSET 36 /* Margins -- */
- #define YOFFSET 36 /* .5 inches each */
- #define PSX XPSSIZE-1
- #define PSY YPSSIZE-1
- #define OF pls->OutFile
- #define MIN_WIDTH 1 /* Minimum pen width */
- #define MAX_WIDTH 10 /* Maximum pen width */
- #define DEF_WIDTH 3 /* Default pen width */
-
- /* These are for covering the page with the background color */
-
- #define XMIN -XOFFSET*ENLARGE
- #define XMAX PSX+XOFFSET*ENLARGE
- #define YMIN -XOFFSET*ENLARGE
- #define YMAX PSY+XOFFSET*ENLARGE
-
- /* Struct to hold device-specific info. */
-
- typedef struct {
- PLFLT pxlx, pxly;
- PLINT xold, yold;
-
- PLINT xmin, xmax, xlen;
- PLINT ymin, ymax, ylen;
-
- PLINT xmin_dev, xmax_dev, xlen_dev;
- PLINT ymin_dev, ymax_dev, ylen_dev;
-
- PLFLT xscale_dev, yscale_dev;
-
- int llx, lly, urx, ury, ptcnt;
- } PSDev;
-
- static char outbuf[128];
-
- /*--------------------------------------------------------------------------*\
- * plD_init_ps()
- *
- * Initialize device.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_init_psm(PLStream *pls)
- {
- pls->color = 0; /* Not a color device */
- ps_init(pls);
- }
-
- void
- plD_init_psc(PLStream *pls)
- {
- pls->color = 1; /* Is a color device */
- ps_init(pls);
- }
-
- static void
- ps_init(PLStream *pls)
- {
- PSDev *dev;
- float pxlx = YPSSIZE/LPAGE_X;
- float pxly = XPSSIZE/LPAGE_Y;
-
- pls->family = 0; /* Doesn't support familying for now */
- pls->dev_fill0 = 1; /* Can do solid fills */
-
- /* Prompt for a file name if not already set */
-
- plOpenFile(pls);
-
- /* Allocate and initialize device-specific data */
-
- if (pls->dev != NULL)
- free((void *) pls->dev);
-
- pls->dev = calloc(1, (size_t) sizeof(PSDev));
- if (pls->dev == NULL)
- plexit("ps_init: Out of memory.");
-
- dev = (PSDev *) pls->dev;
-
- dev->xold = UNDEFINED;
- dev->yold = UNDEFINED;
-
- plP_setpxl(pxlx, pxly);
-
- dev->llx = XPSSIZE;
- dev->lly = YPSSIZE;
- dev->urx = 0;
- dev->ury = 0;
- dev->ptcnt = 0;
-
- /* Rotate by 90 degrees since portrait mode addressing is used */
-
- dev->xmin = 0;
- dev->ymin = 0;
- dev->xmax = PSX;
- dev->ymax = PSY;
- dev->xlen = dev->xmax - dev->xmin;
- dev->ylen = dev->ymax - dev->ymin;
-
- plP_setphy(dev->xmin, dev->xmax, dev->ymin, dev->ymax);
-
- /* Header comments into PostScript file */
-
- fprintf(OF, "%%!PS-Adobe-2.0 EPSF-2.0\n");
- fprintf(OF, "%%%%BoundingBox: \n");
- fprintf(OF, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
-
- fprintf(OF, "%%%%Title: PLplot Graph\n");
- fprintf(OF, "%%%%Creator: PLplot Version %s\n", PLPLOT_VERSION);
- fprintf(OF, "%%%%CreationDate: %s\n", ps_getdate());
- fprintf(OF, "%%%%Pages: (atend)\n");
- fprintf(OF, "%%%%EndComments\n\n");
-
- /* Definitions */
- /* Save VM state */
-
- fprintf(OF, "/PSSave save def\n");
-
- /* Define a dictionary and start using it */
-
- fprintf(OF, "/PSDict 200 dict def\n");
- fprintf(OF, "PSDict begin\n");
-
- fprintf(OF, "/@restore /restore load def\n");
- fprintf(OF, "/restore\n");
- fprintf(OF, " {vmstatus pop\n");
- fprintf(OF, " dup @VMused lt {pop @VMused} if\n");
- fprintf(OF, " exch pop exch @restore /@VMused exch def\n");
- fprintf(OF, " } def\n");
- fprintf(OF, "/@pri\n");
- fprintf(OF, " {\n");
- fprintf(OF, " ( ) print\n");
- fprintf(OF, " ( ) cvs print\n");
- fprintf(OF, " } def\n");
-
- /* n @copies - */
-
- fprintf(OF, "/@copies\n");
- fprintf(OF, " {\n");
- fprintf(OF, " /#copies exch def\n");
- fprintf(OF, " } def\n");
-
- /* - @start - -- start everything */
-
- fprintf(OF, "/@start\n");
- fprintf(OF, " {\n");
- fprintf(OF, " vmstatus pop /@VMused exch def pop\n");
- fprintf(OF, " } def\n");
-
- /* - @end - -- finished */
-
- fprintf(OF, "/@end\n");
- fprintf(OF, " {flush\n");
- fprintf(OF, " end\n");
- fprintf(OF, " PSSave restore\n");
- fprintf(OF, " } def\n");
-
- /* bop - -- begin a new page */
- /* Only fill background if we are using color and if the bg isn't white */
-
- fprintf(OF, "/bop\n");
- fprintf(OF, " {\n");
- fprintf(OF, " /SaveImage save def\n");
- fprintf(OF, " } def\n");
-
- /* - eop - -- end a page */
-
- fprintf(OF, "/eop\n");
- fprintf(OF, " {\n");
- fprintf(OF, " showpage\n");
- fprintf(OF, " SaveImage restore\n");
- fprintf(OF, " } def\n");
-
- /* Set line parameters */
-
- fprintf(OF, "/@line\n");
- fprintf(OF, " {0 setlinecap\n");
- fprintf(OF, " 0 setlinejoin\n");
- fprintf(OF, " 1 setmiterlimit\n");
- fprintf(OF, " } def\n");
-
- /* d @hsize - horizontal clipping dimension */
-
- fprintf(OF, "/@hsize {/hs exch def} def\n");
- fprintf(OF, "/@vsize {/vs exch def} def\n");
-
- /* d @hoffset - shift for the plots */
-
- fprintf(OF, "/@hoffset {/ho exch def} def\n");
- fprintf(OF, "/@voffset {/vo exch def} def\n");
-
- /* Set line width */
-
- fprintf(OF, "/lw %d def\n", (int) (
- (pls->width < MIN_WIDTH) ? DEF_WIDTH :
- (pls->width > MAX_WIDTH) ? MAX_WIDTH : pls->width));
-
- /* Setup user specified offsets, scales, sizes for clipping */
-
- fprintf(OF, "/@SetPlot\n");
- fprintf(OF, " {\n");
- fprintf(OF, " ho vo translate\n");
- fprintf(OF, " XScale YScale scale\n");
- fprintf(OF, " lw setlinewidth\n");
- fprintf(OF, " } def\n");
-
- /* Setup x & y scales */
-
- fprintf(OF, "/XScale\n");
- fprintf(OF, " {hs %d div} def\n", YPSSIZE);
- fprintf(OF, "/YScale\n");
- fprintf(OF, " {vs %d div} def\n", XPSSIZE);
-
- /* Macro definitions of common instructions, to keep output small */
-
- fprintf(OF, "/M {moveto} def\n");
- fprintf(OF, "/D {lineto} def\n");
- fprintf(OF, "/S {stroke} def\n");
- fprintf(OF, "/Z {stroke newpath} def\n");
- fprintf(OF, "/F {fill} def\n");
- fprintf(OF, "/C {setrgbcolor} def\n");
- fprintf(OF, "/G {setgray} def\n");
- fprintf(OF, "/W {setlinewidth} def\n");
- fprintf(OF, "/B {Z %d %d M %d %d D %d %d D %d %d D %d %d closepath} def\n",
- XMIN, YMIN, XMIN, YMAX, XMAX, YMAX, XMAX, YMIN, XMIN, YMIN);
-
- /* End of dictionary definition */
-
- fprintf(OF, "end\n\n");
-
- /* Set up the plots */
-
- fprintf(OF, "PSDict begin\n");
- fprintf(OF, "@start\n");
- fprintf(OF, "%d @copies\n", COPIES);
- fprintf(OF, "@line\n");
- fprintf(OF, "%d @hsize\n", YSIZE);
- fprintf(OF, "%d @vsize\n", XSIZE);
- fprintf(OF, "%d @hoffset\n", YOFFSET);
- fprintf(OF, "%d @voffset\n", XOFFSET);
-
- fprintf(OF, "@SetPlot\n\n");
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_line_ps()
- *
- * Draw a line in the current color from (x1,y1) to (x2,y2).
- \*--------------------------------------------------------------------------*/
-
- void
- plD_line_ps(PLStream *pls, short x1a, short y1a, short x2a, short y2a)
- {
- PSDev *dev = (PSDev *) pls->dev;
- int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
-
- /* Rotate by 90 degrees */
-
- /* plRotPhy(1, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x1, &y1);
- plRotPhy(1, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x2, &y2);*/
-
- if (x1 == dev->xold && y1 == dev->yold && dev->ptcnt < 40) {
- if (pls->linepos + 12 > LINELENGTH) {
- putc('\n', OF);
- pls->linepos = 0;
- }
- else
- putc(' ', OF);
- /* If user changed line width TELL the poor printer also! */
- if (pls->width != plsc->width)
- { sprintf(outbuf," %d W ", (int) plsc->width);
- pls->width=plsc->width;
- pls->linepos += 5;
- }
- sprintf(outbuf, "%d %d D", x2, y2);
- dev->ptcnt++;
- pls->linepos += 12;
- }
- else {
- fprintf(OF, " Z\n");
- pls->linepos = 0;
-
- /* If user changed line width TELL the poor printer also! */
- if (pls->width != plsc->width)
- { sprintf(outbuf," %d W ", (int) plsc->width);
- pls->width=plsc->width;
- pls->linepos += 5;
- }
-
- sprintf(outbuf, "%d %d M %d %d D", x1, y1, x2, y2);
- dev->llx = MIN(dev->llx, x1);
- dev->lly = MIN(dev->lly, y1);
- dev->urx = MAX(dev->urx, x1);
- dev->ury = MAX(dev->ury, y1);
- dev->ptcnt = 1;
- pls->linepos += 24;
- }
- dev->llx = MIN(dev->llx, x2);
- dev->lly = MIN(dev->lly, y2);
- dev->urx = MAX(dev->urx, x2);
- dev->ury = MAX(dev->ury, y2);
-
- fprintf(OF, "%s", outbuf);
- pls->bytecnt += 1 + strlen(outbuf);
- dev->xold = x2;
- dev->yold = y2;
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_polyline_ps()
- *
- * Draw a polyline in the current color.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_polyline_ps(PLStream *pls, short *xa, short *ya, PLINT npts)
- {
- PLINT i;
-
- for (i = 0; i < npts - 1; i++)
- plD_line_ps(pls, xa[i], ya[i], xa[i + 1], ya[i + 1]);
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_eop_ps()
- *
- * End of page.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_eop_ps(PLStream *pls)
- {
- fprintf(OF, " S\neop\n");
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_bop_ps()
- *
- * Set up for the next page.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_bop_ps(PLStream *pls)
- {
- PSDev *dev = (PSDev *) pls->dev;
-
- dev->xold = UNDEFINED;
- dev->yold = UNDEFINED;
-
- pls->page++;
- fprintf(OF, "%%%%Page: %d %d\n", (int) pls->page, (int) pls->page);
- fprintf(OF, "bop\n");
- if (pls->color) {
- float r, g, b;
- if (pls->cmap0[0].r != 0xFF ||
- pls->cmap0[0].g != 0xFF ||
- pls->cmap0[0].b != 0xFF ) {
-
- r = ((float) pls->cmap0[0].r) / 255.;
- g = ((float) pls->cmap0[0].g) / 255.;
- b = ((float) pls->cmap0[0].b) / 255.;
-
- fprintf(OF, "B %.4f %.4f %.4f C F\n", r, g, b);
- }
- }
- pls->linepos = 0;
-
- /* This ensures the color is set correctly at the beginning of each page */
-
- plD_state_ps(pls, PLSTATE_COLOR0);
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_tidy_ps()
- *
- * Close graphics file or otherwise clean up.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_tidy_ps(PLStream *pls)
- {
- PSDev *dev = (PSDev *) pls->dev;
-
- fprintf(OF, "\n%%%%Trailer\n");
-
- dev->llx /= ENLARGE;
- dev->lly /= ENLARGE;
- dev->urx /= ENLARGE;
- dev->ury /= ENLARGE;
- dev->llx += XOFFSET;
- dev->lly += YOFFSET;
- dev->urx += XOFFSET;
- dev->ury += YOFFSET;
-
- /* changed for correct Bounding boundaries Jan Thorbecke okt 1993*/
- /* occurs from the integer truncation -- postscript uses fp arithmetic */
-
- dev->urx += 1;
- dev->ury += 1;
-
- fprintf(OF, "%%%%Pages: %d\n", (int) pls->page);
- fprintf(OF, "@end\n");
-
- /* Backtrack to write the BoundingBox at the beginning */
- /* Some applications don't like it atend */
-
- rewind(OF);
- fprintf(OF, "%%!PS-Adobe-2.0 EPSF-2.0\n");
- fprintf(OF, "%%%%BoundingBox: %d %d %d %d\n",
- dev->llx, dev->lly, dev->urx, dev->ury);
- fclose(OF);
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_state_ps()
- *
- * Handle change in PLStream state (color, pen width, fill attribute, etc).
- \*--------------------------------------------------------------------------*/
-
- void
- plD_state_ps(PLStream *pls, PLINT op)
- {
- PSDev *dev = (PSDev *) pls->dev;
-
- switch (op) {
-
- case PLSTATE_WIDTH:{
- int width =
- (pls->width < MIN_WIDTH) ? DEF_WIDTH :
- (pls->width > MAX_WIDTH) ? MAX_WIDTH : pls->width;
-
- fprintf(OF, " S\n%d W", width);
-
- dev->xold = UNDEFINED;
- dev->yold = UNDEFINED;
- break;
- }
- case PLSTATE_COLOR0:
- if (! pls->color) {
- fprintf(OF, " S\n%.4f G", (pls->icol0 ? 0.0 : 1.0));
- break;
- }
- /* else fallthrough */
- case PLSTATE_COLOR1:
- if (pls->color) {
- float r = ((float) pls->curcolor.r) / 255.0;
- float g = ((float) pls->curcolor.g) / 255.0;
- float b = ((float) pls->curcolor.b) / 255.0;
-
- fprintf(OF, " S\n%.4f %.4f %.4f C", r, g, b);
- }
- else {
- float r = ((float) pls->curcolor.r) / 255.0;
- fprintf(OF, " S\n%.4f G", 1.0 - r);
- }
- break;
- }
-
- /* Reinitialize current point location. */
-
- if (dev->xold != UNDEFINED && dev->yold != UNDEFINED) {
- fprintf(OF, " %d %d M \n", (int)dev->xold, (int)dev->yold);
- }
- }
-
- /*--------------------------------------------------------------------------*\
- * plD_esc_ps()
- *
- * Escape function.
- \*--------------------------------------------------------------------------*/
-
- void
- plD_esc_ps(PLStream *pls, PLINT op, void *ptr)
- {
- switch (op) {
- case PLESC_FILL:
- fill_polygon(pls);
- break;
- }
- }
-
- /*--------------------------------------------------------------------------*\
- * fill_polygon()
- *
- * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
- * Only solid color fill supported.
- \*--------------------------------------------------------------------------*/
-
- static void
- fill_polygon(PLStream *pls)
- {
- PSDev *dev = (PSDev *) pls->dev;
- PLINT n, ix = 0, iy = 0;
- int x, y;
-
- fprintf(OF, " Z\n");
-
- for (n = 0; n < pls->dev_npts; n++) {
- x = pls->dev_x[ix++];
- y = pls->dev_y[iy++];
-
- /* Rotate by 90 degrees */
-
- plRotPhy(1, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x, &y);
-
- /* First time through start with a x y moveto */
-
- if (n == 0) {
- sprintf(outbuf, "%d %d M", x, y);
- dev->llx = MIN(dev->llx, x);
- dev->lly = MIN(dev->lly, y);
- dev->urx = MAX(dev->urx, x);
- dev->ury = MAX(dev->ury, y);
- fprintf(OF, "%s", outbuf);
- pls->bytecnt += strlen(outbuf);
- continue;
- }
-
- if (pls->linepos + 21 > LINELENGTH) {
- putc('\n', OF);
- pls->linepos = 0;
- }
- else
- putc(' ', OF);
-
- pls->bytecnt++;
-
- sprintf(outbuf, "%d %d D", x, y);
- dev->llx = MIN(dev->llx, x);
- dev->lly = MIN(dev->lly, y);
- dev->urx = MAX(dev->urx, x);
- dev->ury = MAX(dev->ury, y);
-
- fprintf(OF, "%s", outbuf);
- pls->bytecnt += strlen(outbuf);
- pls->linepos += 21;
- }
- dev->xold = UNDEFINED;
- dev->yold = UNDEFINED;
- fprintf(OF, " F ");
- }
-
- /*--------------------------------------------------------------------------*\
- * ps_getdate()
- *
- * Get the date and time
- \*--------------------------------------------------------------------------*/
-
- static char *
- ps_getdate(void)
- {
- int len;
- time_t t;
- char *p;
-
- t = time((time_t *) 0);
- p = ctime(&t);
- len = strlen(p);
- *(p + len - 1) = '\0'; /* zap the newline character */
- return p;
- }
-
- #else
- int
- pldummy_ps()
- {
- return 0;
- }
-
- #endif /* PLD_ps */
-